package com.tanhua.app.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.PageUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.app.exception.BusinessException;
import com.tanhua.app.exception.ErrorResult;
import com.tanhua.app.interceptor.UserHolder;
import com.tanhua.commons.utils.Constants;
import com.tanhua.config.template.OssTemplate;
import com.tanhua.dubbo.api.AttentionApi;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VideoApi;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Video;
import com.tanhua.model.pojo.AttentionList;
import com.tanhua.model.pojo.UserInfo;
import com.tanhua.model.vo.CommentVo;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VideoVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class SmallVideosService {

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private FdfsWebServer webServer;

    @Autowired
    private FastFileStorageClient client;

    @DubboReference
    private VideoApi videoApi;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private MqMessageService mqMessageServicel;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private AttentionApi attentionApi;

    @Autowired
    private UserFreezeService userFreezeService;

    //上传小视频
    public void uploadSmallVideos(MultipartFile videoThumbnail, MultipartFile videoFile) throws IOException {
        //如果上传的视频封面或者视频为空则抛出异常
        if (videoThumbnail ==null || videoFile == null){
            throw new BusinessException(ErrorResult.error());
        }
        //将视频上传到FastDFS,获取访问URL
        //获取文件名
        String originalFilename = videoFile.getOriginalFilename();
        //将文件名截取到后缀 Test.java  -> java
        String fileExtName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        StorePath storePath = client.uploadFile(videoFile.getInputStream(),videoFile.getSize(),fileExtName,null);
        String videoUrl = webServer.getWebServerUrl()+storePath.getFullPath();

        //将视频封面上传到阿里oss中
        String picUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());

        //创建小视频对象并保存到MongoDB
        Video video = new Video();
        video.setCreated(System.currentTimeMillis());
        video.setUserId(UserHolder.getUserId());
        video.setText("小视频");
        video.setPicUrl(picUrl);
        video.setVideoUrl(videoUrl);

        String videoId = videoApi.save(video);
        if (StringUtils.isEmpty(videoId)){
            throw new BusinessException(ErrorResult.error());
        }
        mqMessageServicel.sendLogMessage(UserHolder.getUserId(),"0301","video",videoId);
    }

    //分页查询小视频列表
    @Cacheable(
            value="videos",
            key = "T(com.tanhua.app.interceptor.UserHolder).getUserId()+'_'+#page+'_'+#pagesize")
    public PageResult<VideoVo> samllVideoList(Integer page, Integer pagesize) {
        //查询redis中的推荐视频
        String key = Constants.VIDEOS_RECOMMEND+UserHolder.getUserId();
        String value = redisTemplate.opsForValue().get(key);

        List<Video> videoList = new ArrayList<>();
        //redis中的总页数
        int radisPage = 0;
        //判断是否有推荐视频
        if (StringUtils.isNotBlank(value)){
            //如果有推荐视频,查询推荐视频
            //获取推荐数据的vid数组 100002,100003,100004
            String[] vidArr = value.split(",");
            //判断当前页是否有足够数据
            if (vidArr.length > (page-1)*pagesize){
                //对数组进行分页
                List<Long> vids = Arrays.stream(vidArr)
                        .skip((page - 1) * pagesize)
                        .limit(pagesize)
                        .map(vid -> Long.parseLong(vid))
                        .collect(Collectors.toList());

                //根据分页结果 查询推荐视频数据
                videoList = videoApi.findByIds(vids);

            }

            //计算redis的总页数
            radisPage = PageUtil.totalPage(vidArr.length, pagesize);
        }

        //根据redis总页数 查询MongoDB
        if (page > radisPage){
            //如果没有推荐数据,直接分页查询MongoDB
            videoList = videoApi.findByPage(page - radisPage , pagesize);
        }

        List<Long> ids = videoList.stream().map(Video::getUserId).collect(Collectors.toList());
        List<UserInfo> userInfoList = userInfoApi.findByIds(ids);
        Map<Long, UserInfo> map = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity()));

        List<VideoVo> vos = new ArrayList<>();
        for (Video video : videoList) {
            UserInfo userInfo = map.get(video.getUserId());
            VideoVo vo = VideoVo.init(userInfo,video);
            vos.add(vo);
        }

        return new PageResult<VideoVo>(page,pagesize,0,vos);
    }

    //视频点赞
    public void like(String videoId) {
        //判断用户是否点赞
        Boolean hasComment = commentApi.hasComment(videoId, UserHolder.getUserId(), CommentType.LIKE);
        //如果已点赞抛出异常
        if (hasComment){
            throw new BusinessException(ErrorResult.likeError());
        }
        //封装Comment数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(videoId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        commentApi.videoSave(comment);
        //将用户点赞状态存入redis
        String key = Constants.VIDEO_INTERACT_KEY + videoId;
        String hashKey = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().put(key, hashKey, "1");
    }

    //视频取消点赞
    public void dislike(String videoId) {
        //查询用户是否点赞
        Boolean hasComment = commentApi.hasComment(videoId, UserHolder.getUserId(), CommentType.LIKE);
        //如果没点赞 抛出异常
        if (!hasComment) {
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //封装Comment数据
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(videoId));
        comment.setCommentType(CommentType.LIKE.getType());
        comment.setUserId(UserHolder.getUserId());
        comment.setCreated(System.currentTimeMillis());
        commentApi.VideoRemove(comment);
        //删除用户点赞状态
        String key = Constants.VIDEO_INTERACT_KEY + videoId;
        String hashKey = Constants.VIDEO_LIKE_HASHKEY + UserHolder.getUserId();
        redisTemplate.opsForHash().delete(key,hashKey);
    }

    //视频关注
    public void focus(String uid) {
        AttentionList attentionList = attentionApi.findById(UserHolder.getUserId(),uid);
        if (attentionList != null) {
            throw new BusinessException(ErrorResult.error());
        }
        attentionApi.save(UserHolder.getUserId(),uid);
    }

    //视频取消关注
    public void unFocus(String uid) {
        AttentionList attentionList = attentionApi.findById(UserHolder.getUserId(),uid);
        if (attentionList == null) {
            throw new BusinessException(ErrorResult.error());
        }
        attentionApi.delete(UserHolder.getUserId(),uid);
    }

    //视频评论
    public PageResult<CommentVo> comments(Integer page, Integer pagesize, String videoId) {
        //根据videoId查询comment表获取所有评论
        List<Comment> commentList=commentApi.findPagesByMovementId(videoId, CommentType.COMMENT,page,pagesize);
        //判断是否为空
        if (CollUtil.isEmpty(commentList)){
            return new PageResult(page,pagesize,0,null);
        }
        //获取评论人的ids
        List<Long> ids = commentList.stream().map(Comment::getUserId).collect(Collectors.toList());
        //获取评论人的详细信息
        List<UserInfo> userInfoList = userInfoApi.findByIds(ids);
        //将list集合转换成map集合 key是id value是详细信息对象
        Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, Function.identity()));
        List<CommentVo> vos = new ArrayList<>();
        //封装到vo中
        for (Comment comment : commentList) {
            UserInfo userInfo = userInfoMap.get(comment.getUserId());
            if (userInfo != null) {
                CommentVo vo = CommentVo.init(userInfo, comment);

                String key = Constants.MOVEMENTS_INTERACT_KEY+comment.getPublishId();
                String hashKey = Constants.MOVEMENT_COMMENT_LIKE_HASHKEY +UserHolder.getUserId();
                if (redisTemplate.opsForHash().hasKey(key,hashKey)){
                    vo.setHasLiked(1);
                }

                vos.add(vo);
            }
        }
        return new PageResult(page,pagesize,0,vos);
    }

    //视频保存评论
    public void saveComment(String videoId, String comment) {
        //判断是否可以评论
        userFreezeService.freezeCheck(UserHolder.getUserId(),"2");
        Comment newComment = new Comment();
        newComment.setPublishId(new ObjectId(videoId));
        newComment.setCommentType(2);
        newComment.setContent(comment);
        newComment.setUserId(UserHolder.getUserId());
        newComment.setCreated(System.currentTimeMillis());
        commentApi.save(newComment);
    }
}
